Coverage Report

Created: 2025-05-07 21:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\compiler\src\compiler\message.rs
Line
Count
Source
1
// Copyright (c) 2025, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use crate::compiler::builder::FieldBuilder;
30
use crate::compiler::error::Error;
31
use crate::compiler::structure::{FixedFieldType, Structure};
32
use crate::compiler::union::Union;
33
use crate::compiler::util::objects::name_index;
34
use crate::compiler::util::types::{Name, PtrKey};
35
use crate::compiler::Protocol;
36
use crate::model::message::MessageFieldValue;
37
use crate::model::protocol::{Description, Endianness};
38
use crate::model::structure::StructFieldRaw;
39
use bp3d_debug::{error, trace};
40
use std::cell::Cell;
41
use std::fmt::{Display, Formatter};
42
use std::rc::Rc;
43
44
#[derive(Clone, Debug)]
45
pub enum Referenced {
46
    Struct(Rc<Structure>),
47
    Message(Rc<Message>),
48
}
49
50
impl Name for Referenced {
51
37
    fn name(&self) -> &str {
52
37
        match self {
53
27
            Referenced::Struct(v) => &v.name,
54
10
            Referenced::Message(v) => &v.name,
55
        }
56
37
    }
57
}
58
59
impl PtrKey for Referenced {
60
63
    fn ptr_key(&self) -> usize {
61
63
        match self {
62
54
            Referenced::Struct(v) => v.ptr_key(),
63
9
            Referenced::Message(v) => v.ptr_key(),
64
        }
65
63
    }
66
}
67
68
impl Referenced {
69
180
    pub fn lookup(proto: &Protocol, reference_name: &str) -> Option<Self> {
70
180
        proto
71
180
            .structs
72
180
            .get(reference_name)
73
180
            .map(|v| Referenced::Struct(
v117
.
clone117
()))
74
180
            .or_else(|| 
proto.messages63
.
get63
(
reference_name63
).
map63
(|v| Referenced::Message(
v63
.
clone63
())))
75
180
    }
76
}
77
78
#[derive(Clone, Debug)]
79
pub struct FixedContainerField {
80
    pub ty: FixedFieldType,
81
    pub item_type: Rc<Structure>,
82
}
83
84
impl Display for FixedContainerField {
85
10
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
86
10
        write!(f, "FixedContainer<{}, Len = {}>", self.item_type.name, self.ty)
87
10
    }
88
}
89
90
#[derive(Clone, Debug)]
91
pub struct SizedBufferField {
92
    pub ty: FixedFieldType,
93
}
94
95
impl Display for SizedBufferField {
96
14
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
97
14
        write!(f, "Varbuf<{}>", self.ty)
98
14
    }
99
}
100
101
#[derive(Clone, Debug)]
102
pub struct ContainerField {
103
    pub ty: FixedFieldType,
104
    pub item_type: Rc<Message>,
105
    pub nested: bool,
106
}
107
108
impl Display for ContainerField {
109
25
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
110
25
        write!(f, "Container<{}, Len = {}>", self.item_type.name(), self.ty)
111
25
    }
112
}
113
114
#[derive(Clone, Debug)]
115
pub struct SizedContainerField {
116
    pub ty: FixedFieldType,
117
    pub item_type: Rc<Message>,
118
    pub size_ty: FixedFieldType,
119
}
120
121
impl Display for SizedContainerField {
122
9
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
123
9
        write!(
124
9
            f,
125
9
            "SizedContainer<{}, Len = {}, Size = {}>",
126
9
            self.item_type.name(),
127
            self.ty,
128
            self.size_ty
129
        )
130
9
    }
131
}
132
133
#[derive(Clone, Debug)]
134
pub struct FixedField {
135
    pub ty: FixedFieldType,
136
}
137
138
impl Display for FixedField {
139
8
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
140
8
        write!(f, "{}", self.ty)
141
8
    }
142
}
143
144
#[derive(Clone, Debug)]
145
pub struct UnionField {
146
    pub r: Rc<Union>,
147
}
148
149
impl Display for UnionField {
150
8
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
151
8
        f.write_str(self.r.name())
152
8
    }
153
}
154
155
#[derive(Clone, Debug)]
156
pub enum FieldType {
157
    Fixed(FixedField),
158
    Ref(Referenced),
159
160
    /// A buffer field is a field which has a known size which can be determined at runtime
161
    /// (ex: a null-terminated string).
162
    Buffer,
163
164
    /// A sized buffer field is a field which has a known size field based on a configurable type
165
    /// (ex: a Varchar).
166
    SizedBuffer(SizedBufferField),
167
168
    /// A fixed container is a container which can store only fixed size elements (structures).
169
    FixedContainer(FixedContainerField),
170
171
    Union(UnionField),
172
173
    /// A container can store dynamically sized elements.
174
    Container(ContainerField),
175
176
    /// A container which has an additional configurable size field to detect the size in bytes of
177
    /// the container.
178
    SizedContainer(SizedContainerField),
179
180
    Payload,
181
}
182
183
impl Display for FieldType {
184
125
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
185
125
        match self {
186
8
            FieldType::Fixed(v) => v.fmt(f),
187
29
            FieldType::Ref(v) => f.write_str(v.name()),
188
22
            FieldType::Buffer => f.write_str("Buffer"),
189
14
            FieldType::SizedBuffer(v) => v.fmt(f),
190
10
            FieldType::FixedContainer(v) => v.fmt(f),
191
8
            FieldType::Union(v) => v.fmt(f),
192
25
            FieldType::Container(v) => v.fmt(f),
193
9
            FieldType::SizedContainer(v) => v.fmt(f),
194
0
            FieldType::Payload => f.write_str("Bytes"),
195
        }
196
125
    }
197
}
198
199
impl FieldType {
200
55
    pub fn is_message_reference(&self) -> bool {
201
55
        match self {
202
14
            FieldType::Ref(v) => match v {
203
10
                Referenced::Struct(_) => false,
204
4
                Referenced::Message(_) => true,
205
            },
206
41
            _ => false,
207
        }
208
55
    }
209
210
30
    pub fn is_union(&self) -> bool {
211
30
        
matches!16
(self, FieldType::Union(_))
212
30
    }
213
214
69
    pub fn is_string(&self) -> bool {
215
69
        
matches!44
(self, FieldType::SizedBuffer(_) | FieldType::Buffer)
216
69
    }
217
}
218
219
#[derive(Copy, Clone, Debug)]
220
pub struct SizeInfo {
221
    pub is_dyn_sized: bool,
222
    pub is_element_dyn_sized: bool,
223
}
224
225
#[derive(Clone, Debug)]
226
pub struct HeaderField {
227
    pub name: String,
228
    pub index: usize,
229
}
230
231
impl HeaderField {
232
184
    fn from_model(header: Option<String>, fields: &[Field]) -> Result<(Option<Self>, Option<&Field>), Error> {
233
184
        match header {
234
28
            Some(header) => {
235
28
                let (
index27
,
field27
) = fields
236
28
                    .iter()
237
28
                    .enumerate()
238
28
                    .find_map(|(k, v)| if 
v.name == header27
{
Some((k, v))27
} else {
None0
}27
)
  Branch (238:43): [True: 27, False: 0]
  Branch (238:43): [Folded - Ignored]
239
28
                    .ok_or(Error::UndefinedReference(header))
?1
;
240
27
                let header = HeaderField {
241
27
                    index,
242
27
                    name: field.name.clone(),
243
27
                };
244
27
                Ok((Some(header), Some(field)))
245
            }
246
156
            None => Ok((None, None)),
247
        }
248
184
    }
249
}
250
251
#[derive(Clone, Debug)]
252
pub struct Field {
253
    pub name: String,
254
    pub header: Option<HeaderField>,
255
    pub ty: FieldType,
256
    pub optional: bool,
257
    pub size: SizeInfo,
258
    pub endianness: Endianness,
259
    pub description: Option<Description>,
260
    pub codec: Option<String>,
261
}
262
263
impl Display for Field {
264
125
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
265
125
        match (self.optional, &self.codec) {
266
6
            (true, None) => write!(f, "{}: {}?, {} endian", self.name, self.ty, self.endianness),
267
39
            (false, None) => write!(f, "{}: {}, {} endian", self.name, self.ty, self.endianness),
268
15
            (true, Some(v)) => write!(f, "{}: {} ({})?, {} endian", self.name, v, self.ty, self.endianness),
269
65
            (false, Some(v)) => write!(f, "{}: {} ({}), {} endian", self.name, v, self.ty, self.endianness),
270
        }
271
125
    }
272
}
273
274
impl Field {
275
279
    pub fn codec(&self) -> &str {
276
279
        self.codec.as_deref().unwrap_or("base")
277
279
    }
278
279
186
    fn from_model(
280
186
        proto: &Protocol,
281
186
        unsorted: &[Field],
282
186
        has_headers: bool,
283
186
        value: crate::model::message::MessageField,
284
186
    ) -> Result<Self, Error> {
285
186
        if (value.value.is_none() && 
value.item_type48
.
is_none48
())
  Branch (285:13): [True: 48, False: 138]
  Branch (285:38): [True: 1, False: 47]
  Branch (285:13): [Folded - Ignored]
  Branch (285:38): [Folded - Ignored]
286
185
            || (value.value.is_some() && 
value.item_type138
.
is_some138
()) {
  Branch (286:17): [True: 138, False: 47]
  Branch (286:42): [True: 1, False: 137]
  Branch (286:17): [Folded - Ignored]
  Branch (286:42): [Folded - Ignored]
287
2
            return Err(Error::BadFieldType);
288
184
        }
289
184
        let (
header183
,
header_field183
) = HeaderField::from_model(value.header, unsorted)
?1
;
290
183
        if let Some(
field27
) = header_field {
  Branch (290:16): [True: 27, False: 156]
  Branch (290:16): [Folded - Ignored]
291
26
            match &field.ty {
292
26
                FieldType::Ref(Referenced::Struct(v)) => v.set_used_in_header(),
293
1
                v => {
294
1
                    error!(
295
1
                        "Invalid header field type, expected struct reference, got field type {:?}",
296
                        v
297
                    );
298
1
                    return Err(Error::InvalidHeaderType);
299
                }
300
            }
301
156
        }
302
182
        let builder = FieldBuilder::new(value.name, value.optional.unwrap_or_default(), proto.endianness)
303
182
            .description(value.description)
304
182
            .header(header)
305
182
            .codec(value.codec);
306
182
        if let Some(
info135
) = value.value {
  Branch (306:16): [True: 135, False: 47]
  Branch (306:16): [Folded - Ignored]
307
135
            match info {
308
                MessageFieldValue::List {
309
44
                    max_len,
310
44
                    item_type,
311
44
                    max_size,
312
44
                    nested,
313
                } => {
314
44
                    if max_len == 0 {
  Branch (314:24): [True: 1, False: 43]
  Branch (314:24): [Folded - Ignored]
315
1
                        return Err(Error::ZeroArray);
316
43
                    }
317
43
                    if builder.has_codec() {
  Branch (317:24): [True: 0, False: 43]
  Branch (317:24): [Folded - Ignored]
318
0
                        return Err(Error::ForbiddenCodec(builder.name().into()));
319
43
                    }
320
43
                    let r = Referenced::lookup(proto, &item_type).ok_or(Error::UndefinedReference(item_type))
?0
;
321
43
                    let ty = FixedFieldType::from_max_value(max_len)
?0
;
322
43
                    match r {
323
12
                        Referenced::Struct(item_type) => Ok(builder
324
12
                            .codec(Some("list".into()))
325
12
                            .build(FieldType::FixedContainer(FixedContainerField { item_type, ty }))),
326
31
                        Referenced::Message(item_type) => {
327
31
                            if let Some(
max_size7
) = max_size {
  Branch (327:36): [True: 7, False: 24]
  Branch (327:36): [Folded - Ignored]
328
7
                                if max_size == 0 {
  Branch (328:36): [True: 1, False: 6]
  Branch (328:36): [Folded - Ignored]
329
1
                                    return Err(Error::ZeroArray);
330
6
                                }
331
6
                                let size_ty = FixedFieldType::from_max_value(max_size)
?0
;
332
6
                                Ok(builder
333
6
                                    .codec(Some("list".into()))
334
6
                                    .size_info(SizeInfo {
335
6
                                        is_element_dyn_sized: false,
336
6
                                        is_dyn_sized: true,
337
6
                                    })
338
6
                                    .build(FieldType::SizedContainer(SizedContainerField {
339
6
                                        ty,
340
6
                                        item_type,
341
6
                                        size_ty,
342
6
                                    })))
343
                            } else {
344
24
                                item_type.embedded.set(true);
345
24
                                Ok(
346
24
                                    builder.codec(Some("list".into())).dynamic_size().build(FieldType::Container(
347
24
                                        ContainerField {
348
24
                                            ty,
349
24
                                            item_type,
350
24
                                            nested: nested.unwrap_or_default(),
351
24
                                        },
352
24
                                    )),
353
24
                                )
354
                            }
355
                        }
356
                    }
357
                }
358
                MessageFieldValue::Container {
359
12
                    max_len,
360
12
                    item_type,
361
12
                    max_size,
362
12
                    nested,
363
                } => {
364
12
                    if max_len == 0 {
  Branch (364:24): [True: 0, False: 12]
  Branch (364:24): [Folded - Ignored]
365
0
                        return Err(Error::ZeroArray);
366
12
                    }
367
12
                    let r = Referenced::lookup(proto, &item_type).ok_or(Error::UndefinedReference(item_type))
?0
;
368
12
                    let ty = FixedFieldType::from_max_value(max_len)
?0
;
369
12
                    match r {
370
0
                        Referenced::Struct(item_type) => {
371
0
                            Ok(builder.build(FieldType::FixedContainer(FixedContainerField { item_type, ty })))
372
                        }
373
12
                        Referenced::Message(item_type) => {
374
12
                            if let Some(
max_size6
) = max_size {
  Branch (374:36): [True: 6, False: 6]
  Branch (374:36): [Folded - Ignored]
375
6
                                if max_size == 0 {
  Branch (375:36): [True: 0, False: 6]
  Branch (375:36): [Folded - Ignored]
376
0
                                    return Err(Error::ZeroArray);
377
6
                                }
378
6
                                let size_ty = FixedFieldType::from_max_value(max_size)
?0
;
379
6
                                Ok(builder
380
6
                                    .size_info(SizeInfo {
381
6
                                        is_element_dyn_sized: false,
382
6
                                        is_dyn_sized: true,
383
6
                                    })
384
6
                                    .build(FieldType::SizedContainer(SizedContainerField {
385
6
                                        ty,
386
6
                                        item_type,
387
6
                                        size_ty,
388
6
                                    })))
389
                            } else {
390
6
                                item_type.embedded.set(true);
391
6
                                Ok(builder.dynamic_size().build(FieldType::Container(ContainerField {
392
6
                                    ty,
393
6
                                    item_type,
394
6
                                    nested: nested.unwrap_or_default(),
395
6
                                })))
396
                            }
397
                        }
398
                    }
399
                }
400
43
                MessageFieldValue::String { max_len } => {
401
43
                    if builder.has_codec() {
  Branch (401:24): [True: 0, False: 43]
  Branch (401:24): [Folded - Ignored]
402
0
                        return Err(Error::ForbiddenCodec(builder.name().into()));
403
43
                    }
404
43
                    match max_len {
405
33
                        None => Ok(builder.codec(Some("string".into())).build(FieldType::Buffer)),
406
10
                        Some(max_len) => {
407
10
                            if max_len == 0 {
  Branch (407:32): [True: 1, False: 9]
  Branch (407:32): [Folded - Ignored]
408
1
                                return Err(Error::ZeroArray);
409
9
                            }
410
9
                            let ty = FixedFieldType::from_max_value(max_len)
?0
;
411
9
                            Ok(builder
412
9
                                .codec(Some("string".into()))
413
9
                                .build(FieldType::SizedBuffer(SizedBufferField { ty })))
414
                        }
415
                    }
416
                }
417
12
                MessageFieldValue::Buffer { max_len } => match max_len {
418
0
                    None => Ok(builder.build(FieldType::Buffer)),
419
12
                    Some(max_len) => {
420
12
                        if max_len == 0 {
  Branch (420:28): [True: 0, False: 12]
  Branch (420:28): [Folded - Ignored]
421
0
                            return Err(Error::ZeroArray);
422
12
                        }
423
12
                        let ty = FixedFieldType::from_max_value(max_len)
?0
;
424
12
                        Ok(builder.build(FieldType::SizedBuffer(SizedBufferField { ty })))
425
                    }
426
                },
427
15
                MessageFieldValue::Union { name } => {
428
15
                    let 
r14
= proto.unions.get(&name).ok_or(Error::UndefinedReference(name))
?1
;
429
14
                    let 
header_field13
= header_field.ok_or(Error::MissingHeaderForUnion)
?1
;
430
13
                    match &header_field.ty {
431
13
                        FieldType::Ref(Referenced::Struct(v)) => {
432
13
                            if !Rc::ptr_eq(&r.discriminant.root, v) {
  Branch (432:32): [True: 1, False: 12]
  Branch (432:32): [Folded - Ignored]
433
1
                                error!(
434
1
                                    "Union discriminant type mismatch, expected {}, got {}",
435
1
                                    v.name, r.discriminant.root.name
436
                                );
437
1
                                return Err(Error::UnionTypeMismatch);
438
12
                            }
439
                        }
440
0
                        _ => unreachable!(),
441
                    }
442
12
                    if value.optional.unwrap_or_default() {
  Branch (442:24): [True: 0, False: 12]
  Branch (442:24): [Folded - Ignored]
443
0
                        eprintln!("WARNING: ignoring unsupported optional flag on union message field!");
444
12
                    }
445
12
                    Ok(builder.size_info(r.size).build(FieldType::Union(UnionField { r: r.clone() })))
446
                }
447
0
                MessageFieldValue::Payload => Ok(builder.dynamic_size().build(FieldType::Payload)),
448
9
                MessageFieldValue::Unsigned { bits } => {
449
9
                    let ty = FixedFieldType::from_model(StructFieldRaw::Unsigned { bits })
?0
;
450
9
                    Ok(builder.fixed_size().build(FieldType::Fixed(FixedField { ty })))
451
                }
452
            }
453
        } else {
454
47
            let item_type = unsafe { value.item_type.unwrap_unchecked() };
455
47
            let r = Referenced::lookup(proto, &item_type).ok_or(Error::UndefinedReference(item_type))
?0
;
456
47
            match r {
457
39
                Referenced::Struct(r) => {
458
39
                    let is_single = r.fields.len() == 1;
459
39
                    let is_fixed = r.fields[0].ty.as_fixed().is_some();
460
39
                    let is_none = r.fields[0].ty.as_fixed().map(|v| v.raw.is_none()).unwrap_or_default();
461
39
                    let is_byte_aligned = r.fields[0].loc.bit_size % 8 == 0;
462
39
                    trace!({has_headers} {is_single} {is_fixed} {is_none} {is_byte_aligned}, "Found struct reference: {}", r.name);
463
39
                    if !has_headers && 
is_single19
&&
is_fixed7
&&
is_none7
&&
is_byte_aligned7
{
  Branch (463:24): [True: 19, False: 20]
  Branch (463:40): [True: 7, False: 12]
  Branch (463:53): [True: 7, False: 0]
  Branch (463:65): [True: 7, False: 0]
  Branch (463:76): [True: 7, False: 0]
  Branch (463:24): [Folded - Ignored]
  Branch (463:40): [Folded - Ignored]
  Branch (463:53): [Folded - Ignored]
  Branch (463:65): [Folded - Ignored]
  Branch (463:76): [Folded - Ignored]
464
7
                        let fixed = unsafe { r.fields[0].ty.as_fixed().unwrap_unchecked() };
465
7
                        Ok(builder.fixed_size().build(FieldType::Fixed(FixedField { ty: fixed.bits_type })))
466
                    } else {
467
32
                        Ok(builder.fixed_size().build(FieldType::Ref(Referenced::Struct(r))))
468
                    }
469
                }
470
8
                Referenced::Message(r) => Ok(builder.size_info(r.size).build(FieldType::Ref(Referenced::Message(r)))),
471
            }
472
        }
473
186
    }
474
}
475
476
#[derive(Clone, Debug)]
477
pub struct Message {
478
    pub name: String,
479
    pub ty: Option<String>,
480
    pub description: Option<Description>,
481
    pub fields: Vec<Field>,
482
    pub size: SizeInfo,
483
    embedded: Cell<bool>,
484
}
485
486
impl Message {
487
100
    pub(crate) fn is_embedded(&self) -> bool {
488
100
        self.embedded.get()
489
100
    }
490
491
111
    pub fn from_model(proto: &Protocol, value: crate::model::message::Message) -> Result<Message, Error> {
492
111
        let mut fields = Vec::with_capacity(value.fields.len());
493
111
        let mut dyn_sized_elem_count = 0;
494
111
        let mut is_dyn_sized = false;
495
180
        let 
has_headers111
=
value.fields.iter()111
.
any111
(|v| v.header.is_some());
496
287
        for 
v186
in value.fields {
497
186
            let 
field176
= Field::from_model(proto, &fields, has_headers, v)
?10
;
498
176
            if field.size.is_dyn_sized {
  Branch (498:16): [True: 128, False: 48]
  Branch (498:16): [Folded - Ignored]
499
128
                is_dyn_sized = true;
500
128
            
}48
501
176
            if value.ty.is_none() && dyn_sized_elem_count > 0 && (
field.size.is_dyn_sized0
||
field.size.is_element_dyn_sized0
) {
  Branch (501:16): [True: 176, False: 0]
  Branch (501:38): [True: 0, False: 176]
  Branch (501:67): [True: 0, False: 0]
  Branch (501:94): [True: 0, False: 0]
  Branch (501:16): [Folded - Ignored]
  Branch (501:38): [Folded - Ignored]
  Branch (501:67): [Folded - Ignored]
  Branch (501:94): [Folded - Ignored]
502
0
                return Err(Error::VarsizeAfterPayload);
503
176
            }
504
176
            if field.size.is_element_dyn_sized {
  Branch (504:16): [True: 30, False: 146]
  Branch (504:16): [Folded - Ignored]
505
30
                dyn_sized_elem_count += 1;
506
146
            }
507
176
            if value.ty.is_none() && dyn_sized_elem_count > 1 {
  Branch (507:16): [True: 176, False: 0]
  Branch (507:38): [True: 0, False: 176]
  Branch (507:16): [Folded - Ignored]
  Branch (507:38): [Folded - Ignored]
508
0
                return Err(Error::MultiPayload);
509
176
            }
510
176
            fields.push(field);
511
        }
512
101
        Ok(Message {
513
101
            name: value.name,
514
101
            ty: value.ty,
515
101
            description: value.description,
516
101
            fields,
517
101
            size: SizeInfo {
518
101
                is_dyn_sized,
519
101
                is_element_dyn_sized: dyn_sized_elem_count > 0,
520
101
            },
521
101
            embedded: Cell::new(false),
522
101
        })
523
111
    }
524
}
525
526
name_index!(Message => name);